import { hasImports, findAndRemoveImports, openApiCheck, getPageMetadataAndSlug, } from '@mintlify/common';
import { promises as _promises } from 'fs';
import { outputFile } from 'fs-extra';
import { join } from 'path';
import { preparseMdx } from '../../createPage/preparseMdx/index.js';
import { ImportResolver } from './ImportResolver.js';
import { updateConfigFile } from './updateConfigFile.js';
import { updateFavicons } from './updateFavicons.js';
import { updateFiles } from './updateFiles.js';
import { updateGeneratedNav } from './updateGeneratedNav.js';
import { updateOpenApiFiles } from './updateOpenApiFiles.js';
const { readFile } = _promises;
export class UpdateOrchestrator {
    constructor(contentDirectoryPath, staticFilenames, openApiFiles, contentFilenames, snippets, snippetV2Filenames) {
        this.contentDirectoryPath = contentDirectoryPath;
        this.staticFilenames = staticFilenames;
        this.openApiFiles = openApiFiles;
        this.contentFilenames = contentFilenames;
        this.snippets = snippets;
        this.snippetV2Filenames = snippetV2Filenames;
        this.pagesAcc = {};
        this.filesWithImports = [];
    }
    static async update(contentDirectoryPath, staticFilenames, openApiFiles, contentFilenames, snippets, snippetsV2Filenames) {
        return new UpdateOrchestrator(contentDirectoryPath, staticFilenames, openApiFiles, contentFilenames, snippets, snippetsV2Filenames).update();
    }
    async update() {
        const { pagePromises, snippetV2Promises } = this.readFiles();
        const [mintConfig, mdxFilesWithNoImports, snippetV2Contents] = await Promise.all([
            updateConfigFile(this.contentDirectoryPath),
            pagePromises,
            snippetV2Promises,
        ]);
        const [_openapi, pagesAcc] = await Promise.all([
            this.updateOpenApi(mintConfig),
            ImportResolver.writeFiles(this, this.pagesAcc, snippetV2Contents, this.filesWithImports),
        ]);
        this.pagesAcc = pagesAcc;
        await Promise.all([
            updateOpenApiFiles(this.openApiFiles),
            updateGeneratedNav(this.pagesAcc, mintConfig.navigation),
            updateFavicons(mintConfig, this.contentDirectoryPath),
            ...this.writeMdxFilesWithNoImports(mdxFilesWithNoImports),
            ...updateFiles(this.contentDirectoryPath, 'public', [
                ...this.staticFilenames,
                ...this.snippets,
            ]),
        ]);
        return mintConfig;
    }
    readFiles() {
        const pagePromises = this.contentFilenames.map(async (filename) => {
            const sourcePath = join(this.contentDirectoryPath, filename);
            const targetPath = join('src', '_props', filename);
            const contentStr = (await readFile(sourcePath)).toString();
            // if is snippet add to static file array
            const fileContent = await preparseMdx(contentStr, this.contentDirectoryPath, sourcePath);
            const importsResponse = await findAndRemoveImports(fileContent);
            if (hasImports(importsResponse)) {
                this.filesWithImports.push({
                    ...importsResponse,
                    filename,
                });
                return;
            }
            const { slug, pageMetadata } = getPageMetadataAndSlug(filename, contentStr, this.openApiFiles);
            this.pagesAcc = {
                ...this.pagesAcc,
                [slug]: pageMetadata,
            };
            return { targetPath, fileContent };
        });
        const snippetV2Promises = this.snippetV2Filenames.map(async (filename) => {
            const sourcePath = join(this.contentDirectoryPath, filename);
            const contentStr = (await readFile(sourcePath)).toString();
            const fileContent = await preparseMdx(contentStr, this.contentDirectoryPath, sourcePath);
            return { filename, content: fileContent };
        });
        return {
            pagePromises: Promise.all(pagePromises),
            snippetV2Promises: Promise.all(snippetV2Promises),
        };
    }
    writeMdxFilesWithNoImports(mdxFilesWithNoImports) {
        return mdxFilesWithNoImports.map(async (response) => {
            if (response === undefined)
                return;
            const { targetPath, fileContent } = response;
            await outputFile(targetPath, fileContent, {
                flag: 'w',
            });
        });
    }
    async updateOpenApi(mintConfig) {
        // Download OpenApi file if url is provided
        if (mintConfig.openapi &&
            typeof mintConfig.openapi === 'string' &&
            mintConfig.openapi.startsWith('http')) {
            const specFromUrl = await openApiCheck(mintConfig.openapi, true);
            if (specFromUrl) {
                this.openApiFiles.push({
                    filename: 'openapi-from-url',
                    spec: specFromUrl,
                });
            }
            else {
                console.log("OpenApi file couldn't be downloaded from url.");
            }
        }
    }
}
